package com.laolang.thresh.module.auth.logic;

import com.google.common.collect.Maps;
import com.laolang.thresh.framework.common.util.web.ServletUtil;
import com.laolang.thresh.framework.redis.util.RedisUtil;
import com.laolang.thresh.module.auth.business.TokenBusiness;
import com.laolang.thresh.module.auth.consts.AuthRedisConsts;
import com.laolang.thresh.module.auth.consts.SysUserLoginLogConsts.OpSource;
import com.laolang.thresh.module.auth.consts.SysUserLoginLogConsts.OpType;
import com.laolang.thresh.module.auth.dto.LoginUser;
import com.laolang.thresh.module.auth.exception.AuthBusinessException;
import com.laolang.thresh.module.auth.propterties.AuthProperties;
import com.laolang.thresh.module.auth.req.LoginReq;
import com.laolang.thresh.module.auth.rsp.LoginRsp;
import com.laolang.thresh.module.auth.util.AuthUtil;
import com.laolang.thresh.module.system.user.business.SysUserBusiness;
import com.laolang.thresh.module.system.user.entity.SysUser;
import com.laolang.thresh.module.system.user.entity.SysUserLoginLog;
import com.laolang.thresh.module.system.user.service.SysUserLoginLogService;
import eu.bitwalker.useragentutils.UserAgent;
import io.vavr.Tuple2;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;
import javax.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * 鉴权管理实现.
 *
 * @author laolang
 * @version 0.1
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class AuthLogic {

    private final TokenBusiness tokenBusiness;
    private final SysUserBusiness sysUserBusiness;
    private final RedisUtil redisUtil;
    private final AuthProperties authProperties;
    private final SysUserLoginLogService sysUserLoginLogService;
    private final HttpServletRequest request;
    private final AuthUtil authUtil;

    /**
     * 登录.
     */
    public LoginRsp login(LoginReq req) {
        SysUser user = sysUserBusiness.tryGetByUsername(req.getUsername());
        if (Objects.isNull(user)) {
            throw AuthBusinessException.loginFailedUsernamePasswordVerifyFailed();
        }

        // 生成 token
        Map<String, Object> payload = Maps.newHashMap();
        payload.put("id", 1001L);
        payload.put("username", "superAdmin");
        Tuple2<String, String> jwtTuple = tokenBusiness.genJwt(payload,
            user.getJwtSecret());

        LoginRsp rsp = new LoginRsp();
        rsp.setToken(jwtTuple._1);
        rsp.setUuid(jwtTuple._2);

        // 保存 token 信息
        LoginUser loginUser = new LoginUser();
        loginUser.setId(user.getId());
        loginUser.setUsername(user.getUsername());
        loginUser.setTokenUuid(rsp.getUuid());
        loginUser.setTokenValue(rsp.getToken());
        loginUser.setJwtSecret(user.getJwtSecret());
        redisUtil.set(AuthRedisConsts.JWT_PREFIX + rsp.getUuid(), loginUser, authProperties.getAccessExpire() * 60);

        // 保存登录日志
        saveLoginLog(user.getId(), OpType.IN);
        return rsp;
    }

    public void logout() {
        LoginUser loginUser = authUtil.getLoginUser(request);

        // 删除 redis 中的登录信息
        redisUtil.del(AuthRedisConsts.JWT_PREFIX + loginUser.getTokenUuid());

        // 保存登录日志
        saveLoginLog(loginUser.getId(), OpType.OUT);
    }

    private void saveLoginLog(Long userId, OpType type) {
        SysUserLoginLog loginLog = new SysUserLoginLog();
        loginLog.setUserId(userId);
        loginLog.setIp(ServletUtil.getIpAddr(request));
        UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("user-agent"));
        loginLog.setClientType(userAgent.getOperatingSystem().getDeviceType().toString().toLowerCase());
        loginLog.setOs(userAgent.getOperatingSystem().getName());
        loginLog.setBrowser(userAgent.getBrowser().toString().toLowerCase());
        loginLog.setOpDatetime(LocalDateTime.now());
        loginLog.setOpType(type.getCode());
        loginLog.setOpSource(OpSource.USER.getCode());
        sysUserLoginLogService.save(loginLog);
    }
}
